<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    /*
        1.继承基础
            - extends
     */
    // 1.1 
    class Vehicle {

    }

    // 继承类
    class Bus extends Vehicle {

    }

    let b = new Bus();
    console.log(b instanceof Bus)
    console.log(b instanceof Vehicle)

    // 1.2 基础普通构造函数
    function Person() {

    }

    class Engineer extends Person {
    }

    let e = new Engineer();
    console.log(e instanceof Engineer)
    console.log(e instanceof Person)

    // 1.3
    console.log('---1.3---')

    class Vehicle1_3 {
        identifyPrototype(id) {
            console.log('method', id, this)
        }

        static identifyPrototype(id) {
            console.log('static', id, this)
        }
    }

    class Bus1_3 extends Vehicle1_3 {
    }

    let v1_3 = new Vehicle1_3();
    let b1_3 = new Bus1_3();

    b1_3.identifyPrototype('bus')   // method bus Bus1_3{}
    v1_3.identifyPrototype('vehicle')   // method vehicle Vehicle1_3{}

    Bus1_3.identifyPrototype('bus') // static ...
    Vehicle1_3.identifyPrototype('vehicle') // static ...

    /*
        2.构造函数 HomeObject 和super()
            super
                - 只能在派生类构造函数和静态方法中使用(普通方法也可以使用)
                - 不能单独引用super关键字,要么用它调用的构造函数,要么用它引用静态方法
                - 调用super()会调用父类构造函数,并将返回的实例赋值给this
                - 如需给父类构造函数传参,则需要手动传入
                - 如果没有定义类构造函数,在实例化派生类时会调用super(),并且会传入所有传给派生类的参数
                - 在constructor中,不能在调用super()之前引用this
                - 如果在派生类中显式定义了构造函数,则要么必须在其中调用super(),要么必须在其中放回一个对象
     */

    console.log('---2.1---')

    class Vehicle2_1 {
        constructor(value = true) {
            this.hasEngine = value
        }

        static identify() {
            console.log('vehicle')
        }

        getName() {
            console.log('jack')
        }

    }

    class Bus2_1 extends Vehicle2_1 {
        // 不写默认调用
        constructor() {
            // 不要再super()之前引用this
            super(false);
            console.log(this instanceof Vehicle2_1) // true
            console.log(this)       // Bus2_1 {hasEngine:false}
        }

        static identify() {
            super.identify();
        }

        getName() {
            super.getName();
        }
    }

    let bus2_1 = new Bus2_1();
    Bus2_1.identify() // 'vehicle'
    bus2_1.getName(); // 'jack'

    /*
        3.抽象基类
            new.target
     */
    console.log('---3_1---')

    class Vehicle3_1 {
        constructor() {
            console.log([new.target])
            if (new.target === Vehicle3_1) {
                throw new Error('Vehicle cannot be directly instantiated')
            }
            // 还可以检测属性
            /*  if (!this.foo) {
                  throw new Error('Inheriting class must define foo()')
              }*/

        }
    }

    class Bus3_1 extends Vehicle3_1 {

    }

    new Bus3_1();   //  Bus3_1
    try {
        new Vehicle3_1(); // 后面报错
    } catch (e) {

    }

    /*
        4.继承内置类型
     */
    console.log('---4_1---')
    // 4.1
    class SuperArray extends Array {
        shuffle() {
            // 洗牌算法
            for (let i = this.length - 1; i > 0; i--) {
                const j = Math.floor(Math.random() * (i + 1));
                [this[i], this[j]] = [this[j], this[i]]
            }
        }
        
        // 如果想覆盖Symbol.species访问器
        // 这个时候 实例 instanceof SuperArray 为false了
       /* static get [Symbol.species](){
            return Array;
        }*/
    }

    let arr = new SuperArray(1, 2, 3, 4, 5);
    console.log(arr instanceof Array)   // true
    console.log(arr instanceof SuperArray) // true
    console.log(arr)  //  [1,2,3,4,5]
    arr.shuffle();
    console.log(arr) // 随机 [2,4,3,5,1]

    /*
        5.类混入 - 不推荐,就不举例了
     */
    
</script>
</body>
</html>